#!/usr/bin/php
<?php

	namespace aidSQL;

	error_reporting(E_ALL);

	ini_set("display_errors","On");
	ini_set("set_time_limit",'0');
	ini_set("memory_limit",'64M');

	date_default_timezone_set("UTC");

	//This function is included here and not inside the lib/aidSQL/launcher.functions.php
	//because of the simple fact that if a minor version of PHP is running in the system
	//it will error on all of type hints that have namespaces and possibly other interpretation errors

	function checkPHPVersion(){

		$version		= substr(PHP_VERSION,0,strpos(PHP_VERSION,"."));
		$subversion	= substr(PHP_VERSION,strpos(PHP_VERSION,".")+1);
		$subversion	= substr($subversion,0,strpos($subversion,"."));

		if($version != 5 || $subversion < 3){

			return FALSE;

		}

		return TRUE;

	}


	if(!checkPHPVersion()){

		echo "Sorry but you need at least version 5.3.0 in order to run aidSQL :(\n";
		exit(1);

	}


	define ("__CLASSPATH","lib/aidSQL/");

	set_include_path(__CLASSPATH.PATH_SEPARATOR.get_include_path());


	//Interfaces
	require	"interface/Parser.interface.php";
	require	"interface/QueryBuilder.interface.php";
	require	"interface/http/Adapter.interface.php";
	require	"interface/plugin/Injection.interface.php";
	require	"interface/plugin/Info.interface.php";
	require	"interface/db/DbAdapter.interface.php";

	//Core
	require	"class/core/String.class.php";
	require	"class/core/Logger.class.php";
	require	"class/core/File.class.php";
	require	"class/core/Runner.class.php";
	require	"class/core/PluginLoader.class.php";

	//Plugin parent (abstract) classes 
	require	"class/plugin/sqli/InjectionPlugin.class.php";
	require	"class/plugin/sqli/SqliResult.class.php";
	require	"class/plugin/info/InfoPlugin.class.php";
	require	"class/plugin/info/InfoResult.class.php";

	//HTTP 
	require	"class/http/Adapter.class.php";
	require	"class/http/adapter/Ecurl.class.php";
	require	"class/http/Crawler.class.php";
	require	"class/http/ProxyHandler.class.php";
	require	"class/http/webservice/bing/Bing.class.php";
	require	"class/http/webservice/google/Google.class.php";

	//DB related
	require	"class/db/DatabaseSchema.class.php";
	require	"class/db/MySQLDbAdapter.class.php";
	require	"class/db/MySQLQueryBuilder.class.php";
	require	"class/db/MySQLDbBuilder.class.php";

	//Config 
	require	"config/config.php";
	
	//Parsers
	require	"class/parser/Url.class.php";
	require	"class/parser/Dom.class.php";
	require	"class/parser/CmdLine.class.php";		//should be parser/core/CmdLine
	require	"class/parser/Nmap.class.php";			//should be parser/tools/Nmap
	require	"class/parser/Generic.class.php";		//should be parser/sqli/Generic
	require	"class/parser/RevEngXml.class.php";		

	//Functions
	require	"functions/launcher.functions.php";
	require	"functions/log.functions.php";
	require	"functions/misc.functions.php";
	require	"functions/searchEngine.functions.php";

	\start();

	$log	=	new core\Logger();
	$log->setEcho(TRUE);

	try{

		unset($_SERVER["argv"][0]);

		$sites			=	array();
		$links			=	array();

		banner($log);

		if(!hasAcceptedDisclaimer($log)){
			exit(1);
		}

		$log->setPrepend("[aidSQL]");

		$parameters		=	mergeConfig($_SERVER["argv"],"etc/aidSQL/aidSQL.conf");

		$cmdParser		=	new parser\CmdLine();


		$cmdParser->setConfig($config);
		$cmdParser->setCmdLineOptions($parameters);

		//<fixme>
		if(preg_match("/--help-.*/",implode(" ",$parameters))){

			$cmdParser->setOption("url","http://fix.this.awful.regex.org");	
			$pluginHelpFixMe	=	TRUE;
		}
		//</fixme>

		$cmdParser->setIgnoreOptionsWith(
													array(
															"sqli-.*",
															"info-.*"
													)
		);

		$parsedOptions	=	$cmdParser->parse();

		$pluginsDir		=	__CLASSPATH.DIRECTORY_SEPARATOR."class".DIRECTORY_SEPARATOR."plugin";

		$log->reset();
		$log->setColors((bool)$parsedOptions["colors"]);
		$log->setEcho(FALSE);

		$pLoader			=	new \aidSQL\core\PluginLoader($pluginsDir,$log);
		$allPlugins		=	$pLoader->listPlugins();
		$pluginTypes	=	$pLoader->listPluginTypes();
		$pLoader->setConfig($parsedOptions);

		//<plugin-help>

		if(isset($pluginHelpFixMe)){

			foreach($allPlugins as $plugin){

				$help	=	"help-".$plugin["type"].'-'.$plugin["name"];

				if(array_key_exists($help,$parsedOptions)){

					$helpFound	=	TRUE;

					$pLoader->load($plugin);
					$log->setEcho(TRUE);
					$log->setX11Info(FALSE);
					$log->setPrepend("");

					$log->log(strtoupper($plugin["type"] . " " . $plugin["name"] . " HELP")."\n",0,"light_cyan");
					$help	=	'\\'.__NAMESPACE__.'\\plugin\\'.$plugin["type"].'\\'.$plugin["name"]."::getHelp";
					call_user_func($help,$log);
					$log->log("\n");
					exit(0);

				}

			}

			foreach($parameters as $param){

				if(preg_match("/^help-.*/",$param)){
					throw (new \Exception("Help not found for $param!"));
				}

			}

		}

		//</plugin-help>

		//<help>

		if(array_key_exists("help",$parsedOptions)){
			$log->setEcho(TRUE);
			usageLong($log);
			exit(0);
		}	

		//</help>


		$log->setEcho(TRUE);

		if(array_key_exists("list-plugins",$parsedOptions)){

			$log->setPrepend("");
			$log->setX11Info(FALSE);

			foreach($pluginTypes as $pType){

				$log->log(ucwords($pType) . " Plugins",0,"light_green");
				$log->log("-------------------------------------------",0,"light_green");

				foreach($allPlugins as $plugin){

					if($pType==$plugin["type"]){

						$log->log(ucwords($plugin["name"]). "\t\t--help-$pType-$plugin[name] to get help about this plugin",0,"white");
					}

				}
				$log->log("\n");

			}	
			
		}


		if(isset($parsedOptions["log-prepend-date"])){

			$log->useLogDate($parsedOptions["log-prepend-date"]);

		}

		if(!empty($parsedOptions["url"])){

			$sites[0]	=	new \aidSQL\parser\Url($parsedOptions["url"]); 

		}

		//Instance of the http adapter, shared by aggregation through all classes

		//<httpAdapter>

		$Adapter			=	"\\aidSQL\\http\\Adapter\\".$parsedOptions["http-adapter"];
		$httpAdapter	=	new $Adapter();
		$httpAdapter->setMethod($parsedOptions["http-method"]);
		$httpAdapter->setLog($log);
		$httpAdapter->setConfig($parsedOptions);

		if(isset($parsedOptions["proxy-list"])){

			$proxyHandler	=	new \aidSQL\http\ProxyHandler($httpAdapter,$log);
			$proxyHandler->checkProxyList($parsedOptions["proxy-list"]);
			$httpAdapter->setProxyHandler($proxyHandler);

		}

		if(array_key_exists("makedb",$parsedOptions)){

			try{

				$dbMaker	=	new \aidSQL\db\MySQLDbBuilder($parsedOptions,$httpAdapter,$pLoader,$log);

			}catch(Exception $e){

				$log->log($e->getMessage(),1,"red");
				exit(1);

			}

			exit(0);

		}

		//</httpAdapter>


		//<Google>

		if(array_key_exists("google",$parsedOptions)){

			$sites	=	googleSearch($httpAdapter,$log,$parsedOptions);

			if(!sizeof($sites)){

				throw (new \Exception("Google search returned no sites"));

			}

		}

		//</Google>


		//<Bing>

		if(array_key_exists("bing",$parsedOptions)){

			$sites	=	bingSearch($httpAdapter,$log,$parsedOptions);

			if(!sizeof($sites)){

				throw(new \Exception("Bing search returned no sites"));

			}

		}
		//</Bing>


		//<BinGoo>
		if(array_key_exists("bingoo",$parsedOptions)){

			$sites	=	binGoo($httpAdapter,$log,$parsedOptions);

		}
		//</BinGoo>

		if(isset($parsedOptions["shuffle"])){

			shuffle($sites);

		}


		if(isset($parsedOptions["omit-sites"])){

			filterSites($sites,$log,$parsedOptions["omit-sites"]);

		}

		foreach($sites as $url){

			//<urlconfig>

			if(isset($parsedOptions["url-var-separator"])){

				$url->setSeparator=$parsedOptions["url-var-separator"];

			}


			if(isset($parsedOptions["url-query-indicator"])){

				$url->setQueryIndicator($parsedOptions["url-query-indicator"]);

			}


			if(isset($parsedOptions["url-equality-operator"])){

				$url->setEqualityOperator($parsedOptions["url-equality-operator"]);

			}

			//</urlconfig>

			$crawler			=	new http\Crawler($httpAdapter,$url,$log);
			$crawler->setConfig($parsedOptions);

			//To crawl url or not to crawl, that is the question!

			if(!in_array("no-crawl",array_keys($parsedOptions))){

				$log->log("Crawling ...",0,"light_green");

				$log->setEcho(FALSE);

				if($parsedOptions["verbose"]==2){
					$log->setEcho(TRUE);
				}

				$crawler->crawl();

				$log->setEcho(TRUE);

			}

			//Fetch url list, btw this array also contains the current URL, seamless!

			$urls		=	$crawler->getUrlList(TRUE);

			foreach($urls as $key=>$_url){

				if((!$_url["url"]->getQueryAsArray())&&$_url["url"]->getPath()=='/'&&!$_url["url"]->getQueryAsArray()){
					unset($urls[$key]);
				}

			}

			sort($urls);

			if(array_key_exists("list-links",$parsedOptions)){

				$log->log("LINK LIST",0,"light_cyan");
				$log->log("------------------------------------------------",0,"light_cyan");

			}

			$totalVulnerableLinks	=	0;

			if(sizeof($urls)){

				if(array_key_exists("list-links",$parsedOptions)){

					$tmpUrls	=	NULL;

					foreach($urls as $url){
						$tmpUrls[]	=	$url["method"]."}\t\t{".$url["url"];
					}

					if(array_key_exists("interactive",$parsedOptions)){

						$selectedIndexes	=	interactive($log,$tmpUrls);

						foreach($urls as $key=>$url){

								if(!in_array($key,$selectedIndexes)){
									unset($urls[$key]);
								}

						}

					}else{

						exit(0);

					}

				}

				$count	=	1;

				$log->log("Testing links ...",0,"white");
				foreach($urls as $_url){

					$log->log($count++.'. {'.$_url["url"]."}\t\t".'{'.$_url["method"].'}',0,"light_cyan");

					echo $_url["url"]."\n";
					$httpAdapter->setUrl($_url["url"]);

					$httpAdapter->setMethod($_url["method"]);

					$result	=	isVulnerableToSQLInjection($cmdParser,$httpAdapter,$crawler,$log,$pLoader);

					if($result){

						$totalVulnerableLinks++;

						if((bool)$parsedOptions["immediate-mode"]){
							break;
						}


					}else{

						$log->log("Failed to perform injection :(",1,"red");

					}

				}

				\finish($log,$totalVulnerableLinks);

			}else{ //if(sizeof($links))

				$log->setPrepend("[aidSQL]");
				$log->log("Not enough links to check if the site is vulnerable :/",1,"red");

			}

		}

	}catch(\Exception $e){

		$log->setEcho(TRUE);
		$log->log($e->getMessage(),1,"light_red");
		\finish($log);
		exit(1);

	}

?>
